//-----------------------------------------------------------------------------
//	File: i2c.c
//	Author: xialing
//		bsp of soft i2c
//-----------------------------------------------------------------------------

#include "i2c.h"

#define I2C_DELAY_TIMES		16
#define I2C_WAIT_TIMES		1000

// i2c gpio configration
#define I2C_RCC_ALL		RCC_APB2Periph_GPIOE
#define	I2C_SCL_PORT	GPIOE
#define	I2C_SCL_PIN		GPIO_Pin_2
#define	I2C_SDA_PORT	GPIOE
#define	I2C_SDA_PIN		GPIO_Pin_3

// i2c gpio shortcut
#define I2C_SCL_H		(I2C_SCL_PORT->ODR |= I2C_SCL_PIN)
#define I2C_SCL_L		(I2C_SCL_PORT->ODR &= ~I2C_SCL_PIN)
#define I2C_SDA_H		(I2C_SDA_PORT->ODR |= I2C_SDA_PIN)
#define I2C_SDA_L		(I2C_SDA_PORT->ODR &= ~I2C_SDA_PIN)
#define I2C_SDA_IN		((I2C_SDA_PORT->IDR & I2C_SDA_PIN) ? 1u : 0u)

//-----------------------------------------------------------------------------
//	configure_i2c_gpio - configure i2c module gpio
//-----------------------------------------------------------------------------
void configure_i2c_gpio(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

	// enable the peripheral clock
	RCC_APB2PeriphClockCmd(I2C_RCC_ALL, ENABLE);
	// initialize the i2c's pins
	I2C_SCL_H;
	I2C_SDA_H;
	// gpio mode
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	// set the i2c scl pin
	GPIO_InitStructure.GPIO_Pin = I2C_SCL_PIN;
	GPIO_Init(I2C_SCL_PORT, &GPIO_InitStructure);
	// set the i2c sda pin
	GPIO_InitStructure.GPIO_Pin = I2C_SDA_PIN;
	GPIO_Init(I2C_SDA_PORT, &GPIO_InitStructure);
}

//-----------------------------------------------------------------------------
//	i2c_delay - i2c's delay time
//-----------------------------------------------------------------------------
static void i2c_delay(void)
{
	uint16_t us = I2C_DELAY_TIMES;
	while(us--)
		__nop();
}

//-----------------------------------------------------------------------------
//	i2c_start - Generate i2c start flag
//-----------------------------------------------------------------------------
void i2c_start(void)
{
	I2C_SCL_H;
	I2C_SDA_H;
	i2c_delay();
	I2C_SDA_L;
	i2c_delay();
}

//-----------------------------------------------------------------------------
//	i2c_stop - Generate i2c stop flag
//-----------------------------------------------------------------------------
void i2c_stop(void)
{
	I2C_SCL_L;
	I2C_SDA_L;
	i2c_delay();
	i2c_delay();
	I2C_SCL_H;
	i2c_delay();
	I2C_SDA_H;
}

//-----------------------------------------------------------------------------
//	i2c_ack - return the ack status
//-----------------------------------------------------------------------------
uint8_t i2c_ack(void)
{
	return I2C_SDA_IN;
}

//-----------------------------------------------------------------------------
//	i2c_wait_ack - wait the i2c ack
//-----------------------------------------------------------------------------
void i2c_wait_ack(void)
{
	uint16_t i = 0;
	while (I2C_SDA_IN) {
		if (++i == I2C_WAIT_TIMES) return;
	}
}

//-----------------------------------------------------------------------------
//	i2c_write - write data to i2c bus
//		@data: Data or Slave i2c's Address with R/W flag
//		@return: err=1 ok=0
//-----------------------------------------------------------------------------
void i2c_write(uint8_t data)
{
	uint8_t i;

	for (i=0; i<8; i++) {
		i2c_delay();
		I2C_SCL_L;
		i2c_delay();
		(data & 0x80) ? I2C_SDA_H : I2C_SDA_L;
		i2c_delay();
		I2C_SCL_H;
		i2c_delay();
		data <<= 1;
	}

	I2C_SCL_L;
	i2c_delay();
	I2C_SDA_H;
	i2c_delay();
	I2C_SCL_H;
	i2c_delay();
}

//-----------------------------------------------------------------------------
//	i2c_read - read data from i2c bus
//		@pdata: data pointer
//		@len: length of data
//-----------------------------------------------------------------------------
void i2c_read(uint8_t *pdat, uint16_t len)
{
	uint8_t i,temp;

	while (len--) {
		for (i=0; i<8; i++) {
			temp <<= 1;
			i2c_delay();
			I2C_SCL_L;
			i2c_delay();
			I2C_SDA_H;
			i2c_delay();
			I2C_SCL_H;
			i2c_delay();
			temp |= I2C_SDA_IN;
		}

		I2C_SCL_L;
		i2c_delay();
		len ? I2C_SDA_L : I2C_SDA_H;
		i2c_delay();
		I2C_SCL_H;
		i2c_delay();

		*pdat++ = temp;
	}
}

//-----------------------------------------------------------------------------
//	write sample
//-----------------------------------------------------------------------------
/*{
	i2c_start();
	i2c_write(device_write_addr);
	i2c_wait_ack();
	i2c_write(addr);
	i2c_write(data);
	i2c_stop();
}*/

//-----------------------------------------------------------------------------
//	read sample
//-----------------------------------------------------------------------------
/*{
	i2c_start();
	i2c_write(device_write_addr);
	i2c_wait_ack();
	i2c_write(addr);
	i2c_stop();

	i2c_start();
	i2c_write(device_read_addr);
	i2c_read(pdata, len);
	i2c_stop();
}*/

